import itertools
import math
import numpy
import random

class Player():
    def __init__(self):
        self._lambda = 10000.0
        self._rn = 10

    def _adjust(self, val, slacks, Pm1,
            round_number, current_food, current_reputation, m):
        if current_reputation > .9: return val
        adj = 1 + slacks * (current_reputation - 1.0) / Pm1
        return val * adj

    def hunt_choices(self, round_number, current_food,
            current_reputation, m, player_reputations):
        if round_number < self._rn:
            return ['h' for p in player_reputations]

        # Compute probabilities of hunting for each player
        probs = [ r + (0.5 - r) * math.exp(-round_number / self._lambda)
                    for r in player_reputations]

        # Compute the estimated number of hunts needed
        Pm1 = len(player_reputations)
        P = Pm1 + 1
        R = 2 * Pm1
        s = P * Pm1 - m + (Pm1 - 1) * sum(probs)
        s = max(0, int(s)) # back to int

        # Compute the columns probabilities
        Pks = {}
        if P > 10:
            # approximate probabilities since the exact computation
            # would take too long
            lambd = len(probs) - sum(probs) # we are interested in slacks
            ex = math.exp(-lambd)
            term = ex * lambd / 1 # first probability
            for k in range(0, P):
                Pks[k] = term
                # iteratively compute the next term
                term *= lambd / (k + 1)
        else:
            people = range(0, Pm1)
            for k in range(0, P):
                possibleSlackers = itertools.combinations(people, k)
                Pks[k] = 0
                for slackerTeam in possibleSlackers:
                    hunterTeam = []
                    for i in people:
                        if i not in slackerTeam:
                            hunterTeam.append(i)
                    hunterP = [probs[x] for x in hunterTeam]
                    slackerP = [1 - probs[x] for x in slackerTeam]
                    Pks[k] += numpy.prod(hunterP) * numpy.prod(slackerP)

        # Compute the row values: the preferred number of slacks
        vals = {}
        for slacks in range(0, P):
            vals[slacks] = 0
            for k in range(0, P):
                value = slacks - 3 * k
                if slacks + k < s: value += R
                vals[slacks] += value * Pks[k]
            vals[slacks] = self._adjust(vals[slacks], slacks, Pm1,
                    round_number, current_food, current_reputation, m)
        slacks = max(vals, key=lambda x:vals[x])

        # Compute the answer: `slacks' slacks and `Pm1 - slacks' hunts
        answer = 's' * slacks + 'h' * (Pm1 - slacks)
        return answer

    def hunt_outcomes(self, food_earnings):
        pass

    def round_end(self, award, m, number_hunters):
        pass

